////////////////////////////////////////////////////////////////////////////////
/*! \file
 * \brief Enter a brief description here.
 *
 * e
 *
 * \author Ivo Wingelaar
 * \date 2011
 * \version 0.0.1
 * \copyright GNU Lesser General Public License v3
 */
////////////////////////////////////////////////////////////////////////////////

#ifndef __LYNX_COLOR_HPP_INCLUDED__
#define __LYNX_COLOR_HPP_INCLUDED__

////////////////////////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////////////////////////
#include "LynxConfig.hpp"

namespace Lynx
{

////////////////////////////////////////////////////////////////////////////////
//! \brief A color format specifying how color information is stored.
enum E_COLOR_FORMAT
{
    ECF_A1R5G5B5,      ///< 16 bit color format, 5 bits for every color component and a single one for alpha.
    ECF_R5G6B5,        ///< Standard 16 bit color format.
    ECF_R8G8B8,        ///< 24 bit color, no alpha channel, but 8 bit for red, green and blue.
    ECF_A8R8G8B8,      ///< Default 32 bit color format. 8 bits are used for every component.
    ECF_R16F,          ///< 16 bit floating point format using 16 bits for the red channel.
    ECF_G16R16F,       ///< 32 bit floating point format using 16 bits for the red channel and 16 bits for the green channel.
    ECF_A16B16G16R16F, ///< 64 bit floating point format 16 bits are used for the red, green, blue and alpha channels.
    ECF_R32F,          ///< 32 bit floating point format using 32 bits for the red channel.
    ECF_G32R32F,       ///< 64 bit floating point format using 32 bits for the red channel and 32 bits for the green channel.
    ECF_A32B32G32R32F, ///< 128 bit floating point format. 32 bits are used for the red, green, blue and alpha channels.
    ECF_UNKNOWN,       ///< Unknown color format:
    ECF_COUNT          ///< Total size of the enumeration.
};

////////////////////////////////////////////////////////////////////////////////
//! \brief Returns the amount of bits per pixel of the given color format.
/*!
 * \return The bits per pixel.
 *
 * \param[in] format The format you want the bpp from.
 */
inline uint32_t get_bits_per_pixel_from_format(E_COLOR_FORMAT format)
{
    switch(format)
    {
    case ECF_A1R5G5B5:
        return 16;
    case ECF_R5G6B5:
        return 16;
    case ECF_R8G8B8:
        return 24;
    case ECF_A8R8G8B8:
        return 32;
    case ECF_R16F:
        return 16;
    case ECF_G16R16F:
        return 32;
    case ECF_A16B16G16R16F:
        return 64;
    case ECF_R32F:
        return 32;
    case ECF_G32R32F:
        return 64;
    case ECF_A32B32G32R32F:
        return 128;
    default:
        return 0;
    }
}

////////////////////////////////////////////////////////////////////////////////
//! Tests if the color format is only viable for RenderTarget textures
/// \return bool
///         True if the format is only viable for RenderTarget textures.
/// \param    E_COLOR_FORMAT format
///         The format you want the check.
inline bool is_render_target_only_format(E_COLOR_FORMAT format)
{
    switch(format)
    {
    case ECF_A1R5G5B5:
    case ECF_R5G6B5:
    case ECF_R8G8B8:
    case ECF_A8R8G8B8:
        return false;
    default:
        return true;
    }
}

////////////////////////////////////////////////////////////////////////////////
//! Creates a 16 bit A1R5G5B5 color.
/// \return uint16_t
///         A 16 bit A1R5G5B5 color.
/// \param    uint32_t r
///         The red value.
/// \param    uint32_t g
///         The green value.
/// \param    uint32_t b
///         The blue value.
/// \param    uint32_t a
///         The alpha value.
inline uint16_t rgba16(uint32_t r,
                       uint32_t g,
                       uint32_t b,
                       uint32_t a = 0xFF)
{
    return (uint16_t)((a & 0x80) << 8 |
                      (r & 0xF8) << 7 |
                      (g & 0xF8) << 2 |
                      (b & 0xF8) >> 3);
}

////////////////////////////////////////////////////////////////////////////////
//! Creates a 16 bit A1R5G5B5 color.
/// \return uint16_t
///         A 16 bit A1R5G5B5 color.
/// \param    uint32_t r
///         The red value.
/// \param    uint32_t g
///         The green value.
/// \param    uint32_t b
///         The blue value.
inline uint16_t rgb16(uint32_t r,
                      uint32_t g,
                      uint32_t b)
{
    return rgba16(r,g,b);
}


////////////////////////////////////////////////////////////////////////////////
//! Creates a 16bit A1R5G5B5 color, based on 16bit input values.
/// \return uint16_t
///         A 16 bit A1R5G5B5 color.
/// \param    uint16_t r
///         The red value.
/// \param    uint16_t g
///         The green value.
/// \param    uint16_t b
///         The blue value.
inline uint16_t rgb16_from_16(uint16_t r,
                              uint16_t g,
                              uint16_t b)
{
    return (0x8000 |
            (r & 0x1F) << 10 |
            (g & 0x1F) << 5  |
            (b & 0x1F));
}

////////////////////////////////////////////////////////////////////////////////
//! Converts a 32bit (X8R8G8B8) color to a 16bit A1R5G5B5 color.
/// \return uint16_t
///         A 16 bit A1R5G5B5 color.
/// \param    uint32_t color
///         A 32 bit X8R8G8B8 color value.
inline uint16_t x8r8g8b8_to_a1r5g5b5(uint32_t color)
{
    return (uint16_t)(0x8000 |
                      (color & 0x00F80000) >> 9 |
                      (color & 0x0000F800) >> 6 |
                      (color & 0x000000F8) >> 3);
}

////////////////////////////////////////////////////////////////////////////////
//! Converts a 32bit (A8R8G8B8) color to a 16bit A1R5G5B5 color.
/// \return uint16_t
///         A 16 bit A1R5G5B5 color.
/// \param    uint32_t color
///         A 32 bit A8R8G8B8 color value.
inline uint16_t a8r8g8b8_to_a1r5g5b5(uint32_t color)
{
    return (uint16_t)((color & 0x80000000) >> 16|
                      (color & 0x00F80000) >> 9 |
                      (color & 0x0000F800) >> 6 |
                      (color & 0x000000F8) >> 3);
}

////////////////////////////////////////////////////////////////////////////////
//! Converts a 32bit (A8R8G8B8) color to a 16bit R5G6B5 color.
/// \return uint16_t
///         A 16 bit R5G6B5 color.
/// \param    uint32_t color
///         A 32 bit A8R8G8B8 color value.
inline uint16_t a8r8g8b8_to_r5g6b5(uint32_t color)
{
    return (uint16_t)((color & 0x00F80000) >> 8 |
                      (color & 0x0000FC00) >> 5 |
                      (color & 0x000000F8) >> 3);
}

////////////////////////////////////////////////////////////////////////////////
//! Convert A8R8G8B8 Color from A1R5G5B5 color.
/// \return uint32_t
///         A 32 bit A8R8G8B8 color.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline uint32_t a1r5g5b5_to_a8r8g8b8(uint16_t color)
{
    return (((-((int32_t) color & 0x00008000) >> (int32_t) 31) & 0xFF000000) |
            ((color & 0x00007C00) << 9) | ((color & 0x00007000) << 4) |
            ((color & 0x000003E0) << 6) | ((color & 0x00000380) << 1) |
            ((color & 0x0000001F) << 3) | ((color & 0x0000001C) >> 2)
           );
}

////////////////////////////////////////////////////////////////////////////////
//! Returns A8R8G8B8 Color from R5G6B5 color.
/// \return uint32_t
///         A 32 bit A8R8G8B8 color.
/// \param    uint16_t color
///         A 16 bit R5G6B5 color value.
inline uint32_t r5g6b5_to_a8r8g8b8(uint16_t color)
{
    return 0xFF000000 |
           ((color & 0xF800) << 8)|
           ((color & 0x07E0) << 5)|
           ((color & 0x001F) << 3);
}

////////////////////////////////////////////////////////////////////////////////
//! Returns A1R5G5B5 Color from R5G6B5 color.
/// \return uint16_t
///         A 16 bit A1R5G5B5 color.
/// \param    uint16_t color
///         A 16 bit R5G6B5 color value.
inline uint16_t r5g6b5_to_a1r5g5b5(uint16_t color)
{
    return 0x8000 | (((color & 0xFFC0) >> 1) | (color & 0x1F));
}

////////////////////////////////////////////////////////////////////////////////
//! Returns R5G6B5 Color from A1R5G5B5 color.
/// \return uint16_t
///         A 16 bit R5G6B5 color.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline uint16_t a1r5g5b5_to_r5g6b5(uint16_t color)
{
    return (((color & 0x7FE0) << 1) | (color & 0x1F));
}

////////////////////////////////////////////////////////////////////////////////
//! Returns the alpha component from A1R5G5B5 color.
/// \return uint32_t
///         The alpha value.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline uint32_t get_alpha(uint16_t color)
{
    return ((color >> 15)&0x1);
}

////////////////////////////////////////////////////////////////////////////////
//! Returns the red component from A1R5G5B5 color.
/// \return uint32_t
///         The red value.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline uint32_t get_red(uint16_t color)
{
    return ((color >> 10)&0x1F);
}

////////////////////////////////////////////////////////////////////////////////
//! Returns the green component from A1R5G5B5 color.
/// \return uint32_t
///         The green value.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline uint32_t get_green(uint16_t color)
{
    return ((color >> 5)&0x1F);
}

////////////////////////////////////////////////////////////////////////////////
//! Returns the blue component from A1R5G5B5 color.
/// \return uint32_t
///         The blue value.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline uint32_t get_blue(uint16_t color)
{
    return (color & 0x1F);
}

////////////////////////////////////////////////////////////////////////////////
//! Returns the average from a 16 bit A1R5G5B5 color.
/// \return uint32_t
///         The average intensity of the color.
/// \param    uint16_t color
///         A 16 bit A1R5G5B5 color value.
inline int32_t get_average(int16_t color)
{
    return ((get_red(color)<<3) + (get_green(color)<<3) + (get_blue(color)<<3)) / 3;
}

////////////////////////////////////////////////////////////////////////////////
//! A class representing a 32 bit ARGB color.
/*!
 */
class Color
{
public:
    ////////////////////////////////////////////////////////////////////////////
    //! Default constructor.
    /*!
     * Creates a color with all the components set to zero.
     */
    Color() :
        mColor(0)
    {
        //
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Constructor.
    /*!
     * \param[in] a The alpha value in the interval [0, 255]
     * \param[in] r The red value in the interval [0, 255]
     * \param[in] g The green value in the interval [0, 255]
     * \param[in] b The blue value in the interval [0, 255]
     */
    Color(uint8_t a,
          uint8_t r,
          uint8_t g,
          uint8_t b) :
        mColor((a<<24) | (r<<16) | (g<<8) | b)
    {
        //
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Constructor.
    /*!
     * \param[in] color A 32 bit color value.
     */
    Color(uint32_t clr) :
        mColor(clr)
    {
        //
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the alpha value of the color.
    /*!
     * \return The alpha value of the color.
     */
    uint32_t get_alpha(void) const
    {
        return mColor>>24;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the red value of the color.
    /*!
     * \return The red value of the color.
     */
    uint32_t get_red(void) const
    {
        return (mColor>>16) & 0xff;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the green value of the color.
    /*!
     * \return The green value of the color.
     */
    uint32_t get_green(void) const
    {
        return (mColor>>8) & 0xff;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the blue value of the color.
    /*!
     * \return The blue value of the color.
     */
    uint32_t get_blue(void) const
    {
        return mColor & 0xff;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the lightness of the color.
    /// \return float
    ///         The lightness of the color.
    float get_lightness(void) const
    {
        return 0.5f*(Myth::Math::max(Myth::Math::max(get_red(),get_green()),get_blue()) +
                     Myth::Math::min(Myth::Math::min(get_red(),get_green()),get_blue()));
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the luminance of the color.
    /// \return float
    ///         The luminance of the color.
    float get_luminance(void) const
    {
        return 0.3f*get_red() + 0.59f*get_green() + 0.11f*get_blue();
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the average intensity of the color.
    /// \return uint32_t
    ///         The average intensity of the color.
    uint32_t get_average(void) const
    {
        return (get_red() + get_green() + get_blue()) / 3;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Sets the alpha value of the color.
    /// \param    uint32_t a
    ///         The new value you want the alpha component to have.
    void set_alpha(uint32_t a)
    {
        mColor = ((a & 0xff)<<24) | (mColor & 0x00ffffff);
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Sets the red value of the color.
    /// \param    uint32_t r
    ///         The new value you want the red component to have.
    void set_red(uint32_t r)
    {
        mColor = ((r & 0xff)<<16) | (mColor & 0xff00ffff);
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Sets the green value of the color.
    /// \param    uint32_t g
    ///         The new value you want the green component to have.
    void set_green(uint32_t g)
    {
        mColor = ((g & 0xff)<<8) | (mColor & 0xffff00ff);
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Sets the blue value of the color.
    /// \param    uint32_t b
    ///         The new value you want the blue component to have.
    void set_blue(uint32_t b)
    {
        mColor = (b & 0xff) | (mColor & 0xffffff00);
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Calculates a 16 bit A1R5G5B5 value of this color.
    /// \return uint16_t
    ///         16 bit A1R5G5B5 value of this color.
    uint16_t to_a1r5g5b5(void) const
    {
        return a8r8g8b8_to_a1r5g5b5(mColor);
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Converts color to OpenGL color format.
    /// \param    uint8_t* dest
    ///         Address where the 4x8 bit OpenGL color will be stored.
    void to_opengl_color(uint8_t* dest) const
    {
        *dest = (uint8_t)get_red();
        *++dest = (uint8_t)get_green();
        *++dest = (uint8_t)get_blue();
        *++dest = (uint8_t)get_alpha();
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Sets all the 4 color values at once.
    /// \param    uint32_t a
    ///         The alpha value.
    /// \param    uint32_t r
    ///         The red value.
    /// \param    uint32_t g
    ///         The green value.
    /// \param    uint32_t b
    ///         The blue value.
    void set(uint32_t a,
             uint32_t r,
             uint32_t g,
             uint32_t b)
    {
        mColor = (((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff));
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Sets the color value.
    /// \param    uint32_t col
    ///         The value.
    void set(uint32_t col)
    {
        mColor = col;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Compares the color to another color.
    /// \return bool
    ///         True if the colors are the same, false otherwise.
    /// \param    const Color& other
    ///         A reference to the other color.
    bool operator==(const Color& other) const
    {
        return other.mColor == mColor;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Compares the color to another color.
    /// \return bool
    ///         True if the colors are different, false otherwise.
    /// \param    const Color& other
    ///         A reference to the other color.
    bool operator!=(const Color& other) const
    {
        return other.mColor != mColor;
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Compares the color to another color.
    /// \return bool
    ///         True if this color is smaller than the other one, false otherwise.
    /// \param    const Color& other
    ///         A reference to the other color.
    bool operator<(const Color& other) const
    {
        return (mColor < other.mColor);
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Adds the color to another color.
    /// \return Color
    ///         The new added color.
    /// \param    const Color& other
    ///         A reference to the other color.
    Color operator+(const Color& other) const
    {
        return Color(Myth::Math::min(get_alpha() + other.get_alpha(), 255u),
                     Myth::Math::min(get_red() + other.get_red(), 255u),
                     Myth::Math::min(get_green() + other.get_green(), 255u),
                     Myth::Math::min(get_blue() + other.get_blue(), 255u));
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the interpolated color with a f32.
    /// \return Color
    ///         The interpolated color.
    /// \param    const Color& other
    ///         The other color to interpolate with.
    /// \param    float d
    ///         The factor of interpolation.
    Color get_interpolated(const Color& other,
                           float d) const
    {
        d = Myth::Math::clamp(d, 0.f, 1.f);
        const float inv = 1.0f - d;
        return Color((uint32_t)(other.get_alpha()*inv + get_alpha()*d),
                     (uint32_t)(other.get_red()*inv + get_red()*d),
                     (uint32_t)(other.get_green()*inv + get_green()*d),
                     (uint32_t)(other.get_blue()*inv + get_blue()*d));
    }

    ////////////////////////////////////////////////////////////////////////////
    //! Returns the quadratic interpolated color with a f32.
    /// \return Color
    ///         The quadratic interpolated color.
    /// \param    const Color& c1
    ///         The first color to interpolate with.
    /// \param    const Color& c2
    ///         The second color to interpolate with.
    /// \param    float d
    ///         The factor of interpolation.
    Color get_interpolated_quadratic(const Color& c1,
                                     const Color& c2,
                                     float d) const
    {
        d = Myth::Math::clamp(d, 0.f, 1.f);
        const float inv = 1.f - d;
        const float mul0 = inv * inv;
        const float mul1 = 2.f * d * inv;
        const float mul2 = d * d;

        return Color(
                   Myth::Math::clamp(Myth::Math::floor(get_alpha() * mul0 + c1.get_alpha() * mul1 + c2.get_alpha() * mul2), 0, 255),
                   Myth::Math::clamp(Myth::Math::floor(get_red() * mul0 + c1.get_red() * mul1 + c2.get_red() * mul2), 0, 255),
                   Myth::Math::clamp(Myth::Math::floor(get_green() * mul0 + c1.get_green() * mul1 + c2.get_green() * mul2), 0, 255),
                   Myth::Math::clamp(Myth::Math::floor(get_blue() * mul0 + c1.get_blue() * mul1 + c2.get_blue() * mul2), 0, 255));
    }

    uint32_t mColor; ///< The color value.
};

/** class  **/
/** Colorf **/
//! A class representing a color with four floats.
class Colorf
{
public:
    /** default constructor **/
    Colorf() :
        mR(0.0f),
        mG(0.0f),
        mB(0.0f),
        mA(1.0f)
    {
        //
    }

    /** constructor **/
    //! Constructs a color from four float values.
    /// \param    float r
    ///         The red value.
    /// \param    float g
    ///         The green value.
    /// \param    float b
    ///         The blue value.
    /// \param    float a
    ///         The alpha value.
    Colorf(float r,
           float g,
           float b,
           float a = 1.0f) :
        mR(r),
        mG(g),
        mB(b),
        mA(a)
    {
        //
    }

    /** constructor **/
    //! Constructs a color with floats from a 32 bit color.
    /// \param    Color c
    ///         The 32 bit color.
    Colorf(Color c)
    {
        const float inv = 1.0f / 255.0f;
        mR = c.get_red() * inv;
        mG = c.get_green() * inv;
        mB = c.get_blue() * inv;
        mA = c.get_alpha() * inv;
    }

    /** const function **/
    /** to_color       **/
    //! Converts this color with floats to a color without floats.
    /// \return Color
    ///         The color without floats.
    /// \param  void
    Color to_color(void) const
    {
        return Color((uint32_t)(mA*255.0f), (uint32_t)(mR*255.0f), (uint32_t)(mG*255.0f), (uint32_t)(mB*255.0f));
    }

    /** function **/
    /** set      **/
    //! Sets the 3 color values(rgb) at once.
    /// \return void
    /// \param    float r
    ///         The red value.
    /// \param    float g
    ///         The green value.
    /// \param    float b
    ///         The blue value.
    void set(float r,
             float g,
             float b)
    {
        mR = r;
        mG = g;
        mB = b;
    }

    /** function **/
    /** set      **/
    //! Sets all the 4 color values at once.
    /// \return void
    /// \param    float a
    ///         The alpha value.
    /// \param    float r
    ///         The red value.
    /// \param    float g
    ///         The green value.
    /// \param    float b
    ///         The blue value.
    void set(float a,
             float r,
             float g,
             float b)
    {
        mA = a;
        mR = r;
        mG = g;
        mB = b;
    }

    /** const function   **/
    /** get_interpolated **/
    //! Returns the interpolated color with a f32.
    /// \return Colorf
    ///         The interpolated color.
    /// \param    const Colorf& other
    ///         The other color to interpolate with.
    /// \param    float d
    ///         The factor of interpolation.
    Colorf get_interpolated(const Colorf& other,
                            float d) const
    {
        d = Myth::Math::clamp(d, 0.f, 1.f);
        const float inv = 1.0f - d;
        return Colorf(other.mR*inv + mR*d, other.mG*inv + mG*d, other.mB*inv + mB*d, other.mA*inv + mA*d);
    }

    /** const function             **/
    /** get_interpolated_quadratic **/
    //! Returns the quadratic interpolated color with a f32.
    /// \return Colorf
    ///         The quadratic interpolated color.
    /// \param    const Colorf& c1
    ///         The first color to interpolate with.
    /// \param    const Colorf& c2
    ///         The second color to interpolate with.
    /// \param    float d
    ///         The factor of interpolation.
    Colorf get_interpolated_quadratic(const Colorf& c1,
                                      const Colorf& c2,
                                      float d) const
    {
        d = Myth::Math::clamp(d, 0.f, 1.f);
        const float inv = 1.f - d;
        const float mul0 = inv * inv;
        const float mul1 = 2.f * d * inv;
        const float mul2 = d * d;

        return Colorf(mR * mul0 + c1.mR * mul1 + c2.mR * mul2,
                      mG * mul0 + c1.mG * mul1 + c2.mG * mul2,
                      mB * mul0 + c1.mB * mul1 + c2.mB * mul2,
                      mA * mul0 + c1.mA * mul1 + c2.mA * mul2);
    }

    /** const function **/
    /** get_alpha      **/
    //! Returns the alpha value of the color.
    /// \return float
    ///         The alpha value of the color.
    /// \param  void
    float get_alpha(void) const
    {
        return mA;
    }

    /** const function **/
    /** get_red        **/
    //! Returns the red value of the color.
    /// \return float
    ///         The red value of the color.
    /// \param  void
    float get_red(void) const
    {
        return mR;
    }

    /** const function **/
    /** get_green      **/
    //! Returns the green value of the color.
    /// \return float
    ///         The green value of the color.
    /// \param  void
    float get_green(void) const
    {
        return mG;
    }

    /** const function **/
    /** get_blue       **/
    //! Returns the blue value of the color.
    /// \return float
    ///         The blue value of the color.
    /// \param  void
    float get_blue(void) const
    {
        return mB;
    }

    //! The red component of the color.
    float mR;
    //! The green component of the color.
    float mG;
    //! The blue component of the color.
    float mB;
    //! The alpha component of the color.
    float mA;
};

/** class  **/
/** Colorf **/
//! A class representing a color in HSL format.
class ColorHSL
{
public:
    /** constructor **/
    /// \param    float h
    ///         The hue value.
    /// \param    float s
    ///         The saturation value.
    /// \param    float l
    ///         The luminance value.
    ColorHSL(float h = 0.f,
             float s = 0.f,
             float l = 0.f) :
        mHue(h),
        mSaturation(s),
        mLuminance(l)
    {
        //
    }

    /** function **/
    /** from_rgb **/
    //! Creates a color in HSL format from an ordinary color.
    /// \return void
    /// \param    const Color& color
    ///         A const reference to the color you want to convert.
    void from_rgb(const Color& color)
    {
        const float maxVal = (float)Myth::Math::max(color.get_red(), color.get_green(), color.get_blue());
        const float minVal = (float)Myth::Math::min(color.get_red(), color.get_green(), color.get_blue());

        mLuminance = (maxVal/minVal)*0.5f;

        if(Myth::Math::equals(maxVal, minVal))
        {
            mHue = 0.f;
            mSaturation = 0.f;
            return;
        }

        const float delta = maxVal-minVal;
        if(mLuminance <= 0.5f)
            mSaturation = (delta)/(maxVal+minVal);
        else
            mSaturation = (delta)/(2-maxVal-minVal);

        if(maxVal==color.get_red())
            mHue = (color.get_green()-color.get_blue())/delta;
        else if(maxVal==color.get_green())
            mHue = 2+(color.get_blue()-color.get_red())/delta;
        else if(maxVal==color.get_blue())
            mHue = 4+(color.get_red()-color.get_green())/delta;

        mHue *= (60.0f * Myth::Math::DEGTORAD);
        while(mHue < 0.f)
            mHue += 2.f * Myth::Math::PI;
    }

    /** const function **/
    /** to_rgb         **/
    //! Converts this color into an ordinary color.
    /// \return void
    /// \param    Color& color
    ///         The color you want to change.
    void to_rgb(Color& color) const
    {
        if(Myth::Math::is_zero(mSaturation)) // grey
        {
            uint8_t c = (uint8_t)(mLuminance * 255.0);
            color.set_red(c);
            color.set_green(c);
            color.set_blue(c);
            return;
        }

        float rm2;

        if(mLuminance <= 0.5f)
            rm2 = mLuminance + mLuminance * mSaturation;
        else
            rm2 = mLuminance + mSaturation - mLuminance * mSaturation;

        const float rm1 = 2.0f * mLuminance - rm2;

        color.set_red(to_rgb1(rm1, rm2, mHue + (120.0f * Myth::Math::DEGTORAD)));
        color.set_green(to_rgb1(rm1, rm2, mHue));
        color.set_blue(to_rgb1(rm1, rm2, mHue - (120.0f * Myth::Math::DEGTORAD)));
    }

    //! The hue value.
    float mHue;
    //! The saturation value.
    float mSaturation;
    //! The luminance value.
    float mLuminance;

private:
    /** const function **/
    /** to_rgb1        **/
    //! Helper function
    inline uint32_t to_rgb1(float rm1,
                            float rm2,
                            float rh) const
    {
        while(rh > 2.f * Myth::Math::PI)
            rh -= 2.f * Myth::Math::PI;

        while(rh < 0.f)
            rh += 2.f * Myth::Math::PI;

        if(rh < 60.0f * Myth::Math::DEGTORAD)
            rm1 = rm1 + (rm2 - rm1) * rh / (60.0f * Myth::Math::DEGTORAD);
        else if(rh < 180.0f * Myth::Math::DEGTORAD)
            rm1 = rm2;
        else if(rh < 240.0f * Myth::Math::DEGTORAD)
            rm1 = rm1 + (rm2 - rm1) * ((240.0f * Myth::Math::DEGTORAD) - rh) / (60.0f * Myth::Math::DEGTORAD);

        return (uint32_t)(rm1 * 255.f);
    }
};

} // namespace Lynx

#endif // __LYNX_COLOR_HPP_INCLUDED__

